#pragma comment(lib,"glfwdll.lib")
#pragma comment(lib,"opengl32.lib")
#pragma comment( lib, "glew32.lib" )

#define _USE_MATH_DEFINES
#include <math.h>

#include <GL\glew.h>
#define GLFW_NO_GLU
#include <gl\glfw.h>

#include "OpenGLDebug.h"
#include "Shader.h"

#include <sstream>
#include <fstream>
#include <vector>
#include <algorithm>
#include <cassert>

#include "escapi.h"

struct POINT2D
{
	float x;
	float y;

	POINT2D(float x=0, float y=0){
		this->x = x; this-> y = y;
	}
};

struct Point2DInteger
{
	int x;
	int y;

	Point2DInteger(int x=0, int y=0){
		this->x = x; this-> y = y;
	}
};


////////////// NEW!

class OutlineDetector
{
public:
	int width;
	int height;

	std::vector<char> vscreen;
	std::vector<char> trackedCount; // true/false

	Point2DInteger variations_ccw[16]; // counter clockwise traversal
	static const int MAX_PTS=2*4096;
	std::vector<Point2DInteger> points; // store obj outline
	int numPts;

	int errCase15PixelsAllFilled ; // num times occured
	int errCase0PixelsAllEmpty;
	bool marchingSquaresStuck;
	bool gotOutline;

	OutlineDetector(int width=320, int height=240)
	{
		this->width = width;
		this->height = height;

		errCase15PixelsAllFilled = 0; // num times occured
		errCase0PixelsAllEmpty = 0;
		marchingSquaresStuck = false;
		gotOutline = false;

		// Init pixel storage
		vscreen.resize(width*height);
		trackedCount.resize(width*height); // have we tracked NSWE dirs?, 4 dirs for each pixel
		points.resize(MAX_PTS);
		numPts = 0; // number of used points in points vector

		// Make marching squares LUT
		variations_ccw[ 0] = Point2DInteger(0, 0); // illegal
		variations_ccw[ 1] = Point2DInteger(0, 1); // d v
		variations_ccw[ 2] = Point2DInteger(-1, 0); // l <
		variations_ccw[ 3] = Point2DInteger(-1, 0); // l <
		variations_ccw[ 4] = Point2DInteger( 1, 0); // r >
		variations_ccw[ 5] = Point2DInteger( 0, 1); // d v
		variations_ccw[ 6] = Point2DInteger(-1, 0); // l <
		variations_ccw[ 7] = Point2DInteger(-1, 0); // l <
		variations_ccw[ 8] = Point2DInteger( 0,-1); // u ^
		variations_ccw[ 9] = Point2DInteger( 0,-1); // u ^
		variations_ccw[10] = Point2DInteger( 0,-1); // u ^
		variations_ccw[11] = Point2DInteger( 0,-1); // u ^
		variations_ccw[12] = Point2DInteger( 1, 0); // r >
		variations_ccw[13] = Point2DInteger( 0, 1); // d v
		variations_ccw[14] = Point2DInteger( 1, 0); // r >
		variations_ccw[15] = Point2DInteger( 0, 0); // illegal
	}

	// Q: How to get the outlines of solid pixels AND enclosed, internal contours?
	// A: search for entry & exit plus this: if( tracked[x*height+y] ) foundExit = 1; x++; // remeber rewind!

	void getOutline(unsigned char *pixels)
	{
		for(int currentPixel=0; currentPixel<(width * height); currentPixel++)
		{
			//GL_RGBA
			float r = pixels[currentPixel*3+ 0] / 255.0f;
			float g = pixels[currentPixel*3+ 1] / 255.0f;
			float b = pixels[currentPixel*3+ 2] / 255.0f;
			float avg = (r+g+b) / 3.0f;
			if( avg > 0.98)
				vscreen[currentPixel] = 1;
			else
				vscreen[currentPixel] = 0;
		}

		// reset error status
		errCase15PixelsAllFilled = 0; 
		errCase0PixelsAllEmpty = 0;
		marchingSquaresStuck = false;

		int traceCount = 0;

		numPts = 0; // reset

		for(int i=0; i<height*width; i++){  
			trackedCount[i] = 0;  // reset tracked
		}

		for(int y=2; y<height-2; y++)  
			for(int x=2; x<width-2; x++)
			{
				if(vscreen[x*height+y] > 0 && numPts < MAX_PTS)
				{
					if(1) // change between 1 and 0 to choose between find outline only and find outter+internal contours
					{
						if(trackedCount[x*height+y]==0)
						{
							marchingSquares(x,y,traceCount);
							traceCount++;
						}
					}
				} // x
			} // y
	}

	int getNextEdgePoint(int x,int y, int &newx, int &newy)
	{
		int index = 0;
		if( vscreen[(x+1)*height+(y+1)] > 0 ) index += 1;

		if( vscreen[(x)*height+(y+1)] > 0 ) index += 2;

		if( vscreen[(x+1)*height+(y)] > 0 ) index += 4;

		if( vscreen[(x)*height+(y)] > 0 ) index += 8;
		// Error
		if( index==15 ){ errCase15PixelsAllFilled+=1;  }
		if( index==0){ errCase0PixelsAllEmpty+=1; }

		newx += variations_ccw[index].x; 
		newy += variations_ccw[index].y;

		return index;
	}

	void marchingSquares(int x, int y,int traceCount)
	{
		if( numPts >= MAX_PTS) return;

		int posx = x-1; 
		int posy = y-1; // move back and up from pixel
		bool outOfBounds = posx < 1 || posx > (width-2) || posy < 1 || posy > (height-2);
		assert( !outOfBounds );

		int startx = posx; 
		int starty = posy;
		int iters = 0;

		while(iters < MAX_PTS && numPts < MAX_PTS)
		{
			iters++;
			if( iters >= (MAX_PTS-2) ) marchingSquaresStuck++; // either we used all the points exactly (improbabble. or inf loop)
			trackedCount[posx*height+posy] += 1;

			int index = getNextEdgePoint(posx, posy, posx, posy); // Move to next pixel
			outOfBounds = posx < 1 || posx > (width-2) || posy < 1 || posy > (height-2);
			if( outOfBounds ) return;
			if( index==0 || index==15 ) return; // quit if illegal state

			if(trackedCount[posx*width+posy] > 2)
			{
				return;
			}

			if(iters > 1){
				points[numPts].x = posx; points[numPts].y = posy; 
				numPts++;
			}

			if( posx==startx && posy==starty && numPts > 5)
			{
				bool enclosedObject = true;
//				printf("yay?\n");
			}

			// Visualize marching squares progress
			if(false && iters>1)
			{
				if(index==15) glColor3ub(255,255,255); else glColor3ub(255,traceCount,iters%200);
				glBegin(GL_POINTS);
				glVertex2i(posx,posy);   
				glEnd();
				if(iters % 5  == 0)
				{    
					//glfwSwapBuffers();
					//glfwSleep(2.0 / 1000.0);
				}
			}


		}
	}

	void drawOutline()
	{
		glEnable(GL_POINT_SMOOTH);
		glPointSize(3.0);
		glColor3ub(255,255,0);
		glBegin(GL_POINTS);
		for(int i=0; i<numPts; i++)
		{
			glVertex2i( points[i].y, width-points[i].x);
		}
		glEnd();
	}

	void drawScreen()
	{
		glBegin(GL_POINTS);
		for(int y=0; y<height; y++)  
			for(int x=0; x<width; x++)
			{
				if(vscreen[x*height+y] > 0)
				{
					glColor3f(255,255,255);
					glVertex2i(x,y);
				}

			}
			glEnd();
	}

};



////////////// EOF NEW


struct MouseInfo
{
	// A struct to hold mouse data
public:
	int Mx,My;
	bool Mleft, Mright, Mmiddle;

	MouseInfo()
	{
		Mx = My = 0;
		Mleft = Mright = Mmiddle = false;
	}

	MouseInfo copy()
	{
		MouseInfo ret;
		ret.Mx = Mx;
		ret.My = My;
		ret.Mleft = Mleft;
		ret.Mright = Mright;
		ret.Mmiddle = Mmiddle;
		return ret;
	}
};


struct SimpleCapParams capture;
int device;

int xres = 640;
int yres = xres;//240;

int videoWidth = 320;
int videoHeight = videoWidth; 

OutlineDetector outlineDetector(xres,yres);

GLuint screenCaptureTexture;

POINT2D objectCenter;

std::vector<POINT2D> paintLine(1000);
//std::vector<POINT2D> paintLine;

bool Keys[GLFW_KEY_LAST] = {false};  // Key monitor
MouseInfo Mouse; // Mouse monitor
MouseInfo oldMouse;

// Handle keys - updates the Keys array
void KeyCallback(int key, int action)
{
	Keys[key] = (action == GLFW_PRESS);
}

void MouseButtonCallback(int button, int action)
{
	if (button == GLFW_MOUSE_BUTTON_LEFT)
		Mouse.Mleft = (action == GLFW_PRESS);
	else if (button == GLFW_MOUSE_BUTTON_RIGHT)
		Mouse.Mright = (action == GLFW_PRESS); 
	else if (button == GLFW_MOUSE_BUTTON_MIDDLE)
		Mouse.Mmiddle = (action == GLFW_PRESS);     
}

void MousePosCallback(int x, int y)
{
	Mouse.Mx = x;
	Mouse.My = y;
}

void InitWindow(int ScrX, int ScrY, int BPP)
{
	// InitWindow based on GP GLFW tutorial
	// http://gpwiki.org/index.php/OpenGL:Tutorials:Tutorial_Framework:Base#Framework.h_2
	// Initialize the window, may throw if something goes wrong.
	// Initialize the GLFW library
	if (glfwInit() != GL_TRUE)
		throw "Failed to initialize GLFW.";

	// Create a window (8-bit depth-buffer, no alpha and stencil buffers, windowed)
	if (glfwOpenWindow(ScrX, ScrY, BPP/3, BPP/3, BPP/3, 0, 8, 0, GLFW_WINDOW) != GL_TRUE)
		throw "Failed to open window.";

	GLenum err = glewInit();
	if (GLEW_OK != err)
	{
		printf("GLEW ERROR: %s\n", glewGetErrorString(err));
		throw "GLEW Init error";
	}

	if( !GLEW_VERSION_2_1)
	{
		throw "You must have OpenGL 2.1 support to run this program!\n";
	}

	// Give the window a title
	glfwSetWindowTitle("OpenGL Template");

	// Register event callbacks
	glfwSetKeyCallback(KeyCallback);
	glfwSetMouseButtonCallback(MouseButtonCallback);
	glfwSetMousePosCallback(MousePosCallback);
}

void drawQuad(float tx, float ty, float width, float height)
{
	glPushMatrix();
	glTranslatef(tx,ty,0);
	glBegin(GL_QUADS);
	glTexCoord2f(0,0); glVertex2f(0,0);
	glTexCoord2f(1,0); glVertex2f(width,0);
	glTexCoord2f(1,1); glVertex2f(width,height);
	glTexCoord2f(0,1); glVertex2f(0,height);
	glEnd();
	glPopMatrix();
}

void centroidFromTexture(GLubyte *pixels, POINT2D &centroid)
{
	float currentXTotal = 0;
	float currentYTotal = 0;
	float currentPixelTotal = 0;

	//int x = 0;
	//int y = 0;

	for(int currentPixel=0; currentPixel<(xres * yres); currentPixel++)
	{
		//GL_RGBA
		float r = pixels[currentPixel*4+ 0] / 255.0f;
		float g = pixels[currentPixel*4+ 1] / 255.0f;
		float b = pixels[currentPixel*4+ 2] / 255.0f;
		float a = pixels[currentPixel*4+ 3] / 255.0f;

		currentXTotal = currentXTotal + r;
		currentYTotal = currentYTotal + g;
		currentPixelTotal = currentPixelTotal + b;

		//'	setcolor r*255,g*255,b*255
		//'	plot x,y
		//'	x = x+1
		//'	if( x > xres-1)
		//'		x = 0
		//'		y = y+1
		//'endif
	}

	centroid.x = 1.0f - (currentXTotal / currentPixelTotal);
	centroid.y = 1.0f - currentYTotal / currentPixelTotal;
}
void fullScreenRender()
{
	//glDisable(GL_DEPTH_TEST);
	//glMatrixMode(GL_PROJECTION);
	//glLoadIdentity();
	//glMatrixMode(GL_MODELVIEW);
	//glLoadIdentity();

	glColor3ub(255,255,255);
	glActiveTexture(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_2D, screenCaptureTexture);
	glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 0,0, xres, yres, 0);

	glClear(GL_COLOR_BUFFER_BIT);
	glBegin(GL_QUADS);
	//glMultiTexCoord2f(GL_TEXTURE0,0,1); glVertex2i(0,0); //y texcoords are flipped from what you may be used to. compensation for glCopyTexImage2D
	//glMultiTexCoord2f(GL_TEXTURE0,1,1); glVertex2i(xres,0);
	//glMultiTexCoord2f(GL_TEXTURE0,1,0); glVertex2i(xres,yres);
	//glMultiTexCoord2f(GL_TEXTURE0,0,0); glVertex2i(0,yres);
	glMultiTexCoord2f(GL_TEXTURE0,0,0); glVertex2i(0,0); // no flip
	glMultiTexCoord2f(GL_TEXTURE0,1,0); glVertex2i(xres,0);
	glMultiTexCoord2f(GL_TEXTURE0,1,1); glVertex2i(xres,yres);
	glMultiTexCoord2f(GL_TEXTURE0,0,1); glVertex2i(0,yres);
	glEnd();

	//glEnable(GL_DEPTH_TEST);
}


void mainloop()
{
	printf("Press 1 to grab final color\n");
	printf("Press 2 to grab video color\n");
	printf("hold mouse3 to show video frame\n");
	printf("mouse horiz interpolates threshold uniform\n");

	// Create fullscreen render texture
	glActiveTexture(GL_TEXTURE0);
	glEnable(GL_TEXTURE_2D);
	glGenTextures(1, &screenCaptureTexture);
	glBindTexture(GL_TEXTURE_2D, screenCaptureTexture);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);


	// Create video render texture
	glEnable(GL_TEXTURE_2D);
	GLuint videoTexture;
	glGenTextures(1,&videoTexture);
	glBindTexture(GL_TEXTURE_2D,videoTexture);

	// Load up some initial data
	glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,videoWidth,videoHeight,0,GL_RGBA,GL_UNSIGNED_BYTE,(GLvoid*)capture.mTargetBuf);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); // Linear Filtering
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); // Linear Filtering

	// Shaders
	Shader *standardShader = new Shader();
	standardShader->install("shaders/hipass.vert", "shaders/hipass.frag");
	//standardShader->install("shaders/yellow_detector.vert", "shaders/yellow_detector.frag");
	//standardShader->install("shaders/sharpen.vert", "shaders/sharpen.frag");
	//standardShader->install("shaders/dilation.vert", "shaders/dilation.frag");
	//standardShader->install("shaders/ThresholdShader.vert", "shaders/ThresholdShader.frag"); 
	//standardShader->install("shaders/PositionShader.vert", "shaders/PositionShader.frag"); 
	Shader *blurShader = new Shader();
	blurShader->install("shaders/blur.vert", "shaders/blur.frag"); 
	

	glUseProgram(0);

	// glubyte always eq unsigned char?
	std::vector<GLubyte>frameBufferPixels( xres*yres*4);

	glfwSwapInterval(0); // vsync?

	unsigned char bytesRead[3];
	bytesRead[0]=0;
	bytesRead[1]=0;
	bytesRead[2]=0;
	unsigned char finalColor[3];
	finalColor[0]=255;
	finalColor[1]=0;
	finalColor[2]=255;

	float dt = 0.01f;
	float time = (float)glfwGetTime();
	float secondTimer = time+1.0f;
	int fps = 0;
	int frameCount = 0;
	int numframes = 0;
	int running = true;
	std::stringstream ss;
	while( running )
	{
		if( checkGLErrors() )
		{
			bool err = true;
			printf("Houston, we have a problem\n");
		}
		double now = glfwGetTime();
		dt =(float) now - time;
		time =(float) now;
		if( secondTimer < time )
		{
			fps = frameCount;
			frameCount = 0;
			secondTimer = (float)time+1.0f;

			ss << "fps :" << fps;
			std::string title = ss.str();
			ss.str("");
			glfwSetWindowTitle( title.c_str() );
		}
		glMatrixMode(GL_PROJECTION);
		glLoadIdentity();
		glOrtho( 0,xres,yres,0,-1,1 );
		glMatrixMode( GL_MODELVIEW );
		glLoadIdentity();
		glViewport( 0,0,xres,yres );
		glClearColor(0,.6f,0,1);
		glClear(GL_COLOR_BUFFER_BIT);
		//glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

		if( checkGLErrors() )
		{
			bool err = true;

		}

		int numPasses = 3;
		blurShader->begin();
		int UNIFORM_VIDEOFRAME = glGetUniformLocation( blurShader->getProgram(), "videoFrame");
		int UNIFORM_TC = glGetUniformLocation( blurShader->getProgram(), "tc_offset");
		if( UNIFORM_TC != -1 )
		{
			float texCoordOffsets[18];
			float xInc = 1.0f/ float(videoWidth);
			float yInc = 1.0f/ float(videoHeight);

			for(int i=0; i<2; i++)
			{
				for(int j=0; j<2; j++) 
				{
					texCoordOffsets[(((i*3)+j)*2)+0] = (-1.0f * xInc) + ( float(i) * xInc);
					texCoordOffsets[(((i*3)+j)*2)+1] = (-1.0f * yInc) + ( float(j) * yInc);
				}
			}
			glUniform2fv( UNIFORM_TC, 9, texCoordOffsets );
		}
		
		glUniform1i(UNIFORM_VIDEOFRAME, 0);	 // tex unit 0
		
			glEnable(GL_TEXTURE_2D);
			glColor3f(1,1,1);
			glBindTexture(GL_TEXTURE_2D, videoTexture );
			drawQuad(0,0,(float)xres, (float)yres);
	
			fullScreenRender();

		blurShader->end();
		
		if( Keys['2'] )
		{	
			glReadPixels(Mouse.Mx, Mouse.My, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, bytesRead);
			std::cout << "actual VideoColor: " << bytesRead[0]/255.0f << " " << bytesRead[1]/255.0f << " " << bytesRead[2]/255.0f << std::endl ;
		}

		standardShader->begin();
		int uniformLoc = glGetUniformLocation( standardShader->getProgram(), "videoFrame");
		glUniform1i(uniformLoc, 0);	 // tex unit 0

		int UNIFORM_INPUTCOLOR = glGetUniformLocation( standardShader->getProgram(), "inputColor");
		float thresholdColor[3];
		thresholdColor[0] = finalColor[0] / 255.0f;
		thresholdColor[1] = finalColor[1] / 255.0f;
		thresholdColor[2] = finalColor[2] / 255.0f;
		glUniform4f(UNIFORM_INPUTCOLOR, thresholdColor[0], thresholdColor[1], thresholdColor[2], 1.0);

		int UNIFORM_THRESHOLD = glGetUniformLocation( standardShader->getProgram(), "threshold");
		float thresholdSensitivity = Mouse.Mx / float(xres);
		glUniform1f(UNIFORM_THRESHOLD, thresholdSensitivity);	

		fullScreenRender();
		standardShader->end();

		glBindTexture(GL_TEXTURE_2D, screenCaptureTexture );
		//glReadPixels(0,0, xres, yres, GL_RGBA, GL_UNSIGNED_BYTE, &frameBufferPixels[0]);
		//centroidFromTexture(&frameBufferPixels[0], objectCenter);
		
		// for outline detector, we only need RGB
		glReadPixels(0,0, xres, yres, GL_RGB, GL_UNSIGNED_BYTE, &frameBufferPixels[0]);
		outlineDetector.getOutline(&frameBufferPixels[0]);
		
		//glDisable(GL_TEXTURE_2D);

		// Draw original video frame
		if( Mouse.Mleft )
		{
			glBindTexture(GL_TEXTURE_2D, videoTexture );
			//drawQuad(0,0,(float)xres, (float)yres);
			float tx=0; float ty=0; float width=(float)xres; float height = (float)yres;
			glPushMatrix();
			glTranslatef(tx,ty,0);
			glBegin(GL_QUADS);
			glTexCoord2f(0,0); glVertex2f(0,0);
			glTexCoord2f(1,0); glVertex2f(width,0);
			glTexCoord2f(1,1); glVertex2f(width,height);
			glTexCoord2f(0,1); glVertex2f(0,height);
			glEnd();
			glPopMatrix();
		}

		// Get Color of Final output
		if( Keys['1']  )
		{	
			glReadPixels(Mouse.Mx, yres - Mouse.My, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, finalColor);
			std::cout << "final VideoColor: " << finalColor[0]/255.0f << " " << finalColor[1]/255.0f << " " << finalColor[2]/255.0f << std::endl ;
		}

		//glEnable(GL_TEXTURE_2D);
		//glBindTexture(GL_TEXTURE_2D, screenCaptureTexture );
		//drawQuad(0,0,xres,yres);

		

		glDisable(GL_TEXTURE_2D);
		//glClearColor(0,0,0,1);
		//glClear(GL_COLOR_BUFFER_BIT);
		outlineDetector.drawOutline();

		glColor3ubv( finalColor );
		glRectf(0,0,20,20);
		glColor3ubv( bytesRead );
		glRectf(0,20,20,40);

		glColor3f(255,0,0);
		glRectf(xres*objectCenter.x-5, yres*objectCenter.y-5, xres*objectCenter.x+5, yres*objectCenter.y+5);


		// "Delete" linestrip. Justs moves all points out if frame
		if( Keys[GLFW_KEY_DEL] )
		{
			for(size_t i=0; i<paintLine.size(); i++)
			{
				paintLine[i].x = -1;
				paintLine[i].y = -1;
			}
		}

		if( Keys[GLFW_KEY_SPACE])
		{
			POINT2D newP;
			newP.x = xres*objectCenter.x;
			newP.y = yres*objectCenter.y;
			paintLine.front().x = newP.x;
			paintLine.front().y = newP.y;

			for(int i=paintLine.size()-1; i>0; i--)
			{
				paintLine[i] = paintLine[i-1];
			}
		}

		glLineWidth(1.8f);
		glColor3f(1,1,0);
		glBegin(GL_LINE_STRIP);
		for(size_t i=0; i<paintLine.size()-1; i++)
		{
			glVertex2f( paintLine[i].x, paintLine[i].y );
		}
		glEnd();

		frameCount++;
		numframes++;
		bool glErr = checkGLErrors();
		if(glErr)
		{
			printf("gl error\n");
		}
		glfwSwapBuffers();
		//glfwSleep(1.0 / 1000.0); // 1 msec

		if(Keys['R'])
		{
			standardShader->reload();
			blurShader->reload();
		}

		int i;
		if (isCaptureDone(device))
		{
			// OpenGL red and blue are swapped, so we'll need to do some converting here..
			for (i = 0; i < videoWidth*videoHeight; i++)
				capture.mTargetBuf[i] = (capture.mTargetBuf[i] & 0xff00ff00) |
				((capture.mTargetBuf[i] & 0xff) << 16) |
				((capture.mTargetBuf[i] & 0xff0000) >> 16);

			// Load up the new data
			glEnable(GL_TEXTURE_2D);
			glBindTexture(GL_TEXTURE_2D, videoTexture );
			glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,videoWidth,videoHeight,0,GL_RGBA,GL_UNSIGNED_BYTE,(GLvoid*)capture.mTargetBuf);

			// ..and ask for more
			doCapture(device);
		}

		

		if( glfwGetKey(GLFW_KEY_ESC) || !glfwGetWindowParam(GLFW_OPENED) )
		{
			running = false;
		}
	}

}

void initEscapi()
{

	device = setupESCAPI();
	if (device < 1)
	{
		fprintf(stderr, "Unable to init ESCAPI\n");
		//MessageBox(NULL, "DO you have a webcam connected?", "Err", MB_ICONERROR); // req. windows.h?
		system("pause");

		exit(1);
	}

	// Use the second device if more than one found
	// (makes my personal test setup easier =)
	if (device > 1)
		device = 1;
	else
		device = 0;

	// Setup ESCAPI to capture a 256x256 image.
	capture.mWidth = videoWidth;
	capture.mHeight = videoHeight;
	capture.mTargetBuf = new int[videoWidth*videoHeight];
	initCapture(device,&capture);
	doCapture(device);
}

int main()
{
	initEscapi();

	int retval = 0;
	try
	{
		// Initialize the window
		InitWindow(xres,yres,24);
		// Pass control to the render function
		mainloop();
	}
	catch (const char* error)
	{
		// Report an error
		std::ofstream error_file("GL_ERROR.txt");
		error_file << "Caught exception:\n  " << error << '\n';
		retval = 1;
	}

	glfwTerminate();
	return retval;
}